<?php

namespace app\index\controller;

use think\facade\Hook;
use think\Db;
use app\common\facade\Message;
use app\common\service\EsTool;
use think\Console;

use Phpml\Classification\KNearestNeighbors;
use Phpml\Association\Apriori;
use Phpml\Regression\LeastSquares;
use Phpml\Math\Statistic\StandardDeviation;
use Phpml\Math\Statistic\Correlation;
use Phpml\Classification\SVC;
use Phpml\Classification\NaiveBayes;
use Phpml\SupportVectorMachine\Kernel;
use QL\QueryList;
use kafka\KafKa_Lite;

class Test
{

    public function testCfRecommend()
    {
        $url = "http://127.0.0.1:6016/cf_recommend";
        $params = [
            "msg" => "cf_recommend",
            "raw_uid" => "b80344d063b5ccb3212f76538f3d9e43d87dca9e"
        ];
        $res = httpsRequest($url, $params, 'json');

        $list = json_decode($res, true);

        return $list;
    }

    public function testClassAlias()
    {
        $mpdf = new \Mpdf\Mpdf();
        $mpdf->autoScriptToLang = true;
        $mpdf->autoLangToFont = true;
        $mpdf->WriteHTML('<h1>Hello world! 我的朋友</h1>');
        $mpdf->Output();
        die;

        $str = "('hello world)";

        $arr = preg_split('/(")/i', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

        return $arr;

        return strpos($str, "o");

        return "hello world";

        return array_change_key_case(["name" => "test", "property" => 15]);


        $url = "www.zerofc.cn/de/fee/fdfdfd#huf?gods=name&de=fdfd";
        var_dump(parse_url($url));die;

        $ids = "1,2,3,4,5,6,7,8";
        $de = explode(",", $ids, 10);
        return $ids;
        return strlen($ids);

        $reflection = new \ReflectionFunction("User");

        $res = class_alias("think\Db", "alias");
        var_dump($res);die;
    }

    // 消息生产
    public function kafkaTest()
    {
        $rk = new \RdKafka\Producer();
        $rk->addBrokers("127.0.0.1:9092");
        $topic = $rk->newTopic("shop");

        $ret = [];
        for ($i = 0; $i < 5; $i++) {
            $content = "第" . $i . "次发送失败";
            $message = ["mobile" => "15623652142", "content" => $content];
            $payload = json_encode($message);

            // 指定向0号partition生产数据
            $ret[]['produce_res'] = $topic->produce(0, 0, $payload, "sms_$i");

            // 随机选择partition
            //$topic->produce(RD_KAFKA_PARTITION_UA, 0, $payload);
            if ($rk->getOutQLen() > 0) {
                $ret[]['produce_poll'] = $rk->poll(500);
            } else {
                $ret[]['produce_poll'] = $rk->poll(0);
            }
        }

        dump($ret);
    }

    // public function kafkaTest()
    // {
    //     // 配置KafKa集群(默认端口9092)通过逗号分隔
    //     $KafKa_Lite = new KafKa_Lite("127.0.0.1,localhost");
    //
    //     // 设置一个Topic
    //     $KafKa_Lite->setTopic("test");
    //
    //     // 单次写入效率ok  写入1w条15 毫秒
    //     $Producer = $KafKa_Lite->newProducer();
    //
    //     // 参数分别是partition,消息内容,消息key(可选)
    //     // partition:可以设置为KAFKA_PARTITION_UA会自动分配,比如有6个分区写入时会随机选择Partition
    //     $res = $Producer->setMessage(0, "hello");
    //
    //     return $res;
    // }

    // public function kafkaTest()
    // {
    //     //dump(get_declared_classes());die;
    //     $rk = new \RdKafka\Producer();
    //     //$rk->setLogLevel(LOG_DEBUG);
    //     $rk->addBrokers("127.0.0.1");
    //
    //     $topic = $rk->newTopic("shop");
    //
    //     for ($i = 0; $i < 10; $i++) {
    //         $topic->produce(RD_KAFKA_PARTITION_UA, 0, "发送信息： $i");
    //         $rk->poll(0);
    //     }
    //
    //     while ($rk->getOutQLen() > 0) {
    //         $rk->poll(50);
    //     }
    // }

    public function testMongoDbQuery()
    {
        $manager = new \MongoDB\Driver\Manager("mongodb://localhost:27017");

        $filter = ['x' => ['$gt' => 0]];
        $options = [
            'projection' => ['_id' => 0],
            'sort' => ['x' => -1],
        ];

        // 查询数据
        $query = new \MongoDB\Driver\Query($filter, $options);
        $cursor = $manager->executeQuery('test.sites', $query);

        foreach ($cursor as $document) {
            print_r($document);
        }
    }

    public function testMongoDbInsert()
    {
        // 通过用户对商品的操作记录，发布，浏览，评论，点赞，下单等
        // 记录当前用户ID，当前机器ID，根据操作类型进行打分存入mongoDb
        $manager = new \MongoDB\Driver\Manager("mongodb://localhost:27017");

        $bulk = new \MongoDB\Driver\BulkWrite;
        // mongoDb默认存在一个自增长的字符串ID
        $document = [
            '_id' => new \MongoDB\BSON\ObjectID,
            'videoId' => mt_rand(1, 99999),
            'userId' => mt_rand(1, 9999),
            'score' => floatval(mt_rand(5, 100)),
            'date' => time()
        ];
        $bulk->insert($document);
        $res = $manager->executeBulkWrite('tanhua.recommend_video_20191001', $bulk);

        return $res;
    }

    public function testMongoDbBulk()
    {
        //return get_declared_classes();
        $manager = new \MongoDB\Driver\Manager("mongodb://localhost:27017");

        $bulk = new \MongoDB\Driver\BulkWrite;
        $bulk->insert(['x' => 1, 'name' => 'tenent', 'url' => 'http://www.runoob.com']);
        $bulk->insert(['x' => 2, 'name' => 'Google', 'url' => 'http://www.google.com']);
        $bulk->insert(['x' => 3, 'name' => 'taobao', 'url' => 'http://www.taobao.com']);
        $res = $manager->executeBulkWrite('test.sites', $bulk);

        return $res;

        // 插入数据
        // $bulk = new \MongoDB\Driver\BulkWrite;
        // $bulk->insert(['x' => 1, 'name'=>'tenent', 'url' => 'http://www.runoob.com']);
        // $bulk->insert(['x' => 2, 'name'=>'Google', 'url' => 'http://www.google.com']);
        // $bulk->insert(['x' => 3, 'name'=>'taobao', 'url' => 'http://www.taobao.com']);
        // $res = $manager->executeBulkWrite('test.sites', $bulk);
        //
        // return $res;
    }

    // 天气预测
    public function leastSquaresTest()
    {
        // $url = 'https://www.keyunzhan.com/lishitianqi/guangzhou/';
        // $high = QueryList::get($url)->find('table.yuBaoTable')->find('tr')->map(function ($tr) {
        //     return $tr->find('td:eq(1)')->texts();
        // });
        //
        // $targets = $high->toArray();
        // foreach ($targets as &$target){
        //     $target = intval($target[0]);
        // }
        // unset($target);
        // array_shift($targets);
        // $total = count($targets);
        //
        // $samples = [];
        // for($i=0;$i<$total;$i++){
        //     $samples[] = [$i];
        // }

        $samples = [[1], [2], [3], [4], [5], [6]];
        $targets = [18, 20, 21, 18, 16, 19];
        $regression = new LeastSquares();
        $regression->train($samples, $targets);

        //$nextDay = $total+1;
        $nextDay = 7;
        $nextDayHigh = $regression->predict([$nextDay]);

        echo 'next day : ';
        echo(round($nextDayHigh));
        echo chr(10);
    }

    /*********************************************************php-ml业务智能测试*******************************************************/

    // 近邻算法，$samples是数据，$labels是标记，传入的参数[3,2]由模型训练获得结果最靠近d。
    // K-NN 分类，输入：包含特征空间中的 k 个最接近的训练样本。 输出：一个分类族群。
    public function kNearestNeighbors()
    {
        $samples = [[1, 3], [1, 4], [2, 4], [3, 1], [4, 1], [4, 2]];
        $labels = ['a', 'b', 'c', 'd', 'e', 'f'];

        $classifier = new KNearestNeighbors();
        $classifier->train($samples, $labels);

        echo $classifier->predict([3, 2]);
    }

    // 线性 ，近邻居，贝叶斯
    public function naiveBayes()
    {
        /*
        说一个班级里面有三个男生（男生1、男生2,男生3），三个女生（女生1、女生2,女生3），其中
        男生1 身高：176cm 体重：70kg；
        男生2 身高：180cm 体重：80kg；
        男生2 身高：186cm 体重：86kg；
        女生1 身高：161cm 体重：45kg；
        女生2 身高：163cm 体重：47kg；
        女生3 身高：165cm 体重：49kg；
        如果我们将男生定义为1，女生定义为-1(这里定义数值无所谓，你可以定义男生8，女生6，只要是数值就行)
        */
        $samples = [[176, 70], [180, 80], [161, 45], [163, 47], [186, 86], [165, 49]];
        $labels = [1, 1, -1, -1, 1, -1];

        /*
         * 线性分类
         * */
        $classifier = new SVC(Kernel::LINEAR, $cost = 1000);

        /* 对其进行训练   */
        $classifier->train($samples, $labels);

        /*预测190cm高 80kg的人，是男还是女*/
        echo $classifier->predict([190, 80]); //线性分类,输出1，预测结果为男性

        /*
         * KNN-分类
         * */
        $classifier = new KNearestNeighbors();

        /* 对其进行训练   */
        $classifier->train($samples, $labels);

        /*预测190cm高 80kg的人，是男还是女*/
        echo $classifier->predict([190, 80]); //输出1,近邻算法预测结果也为男性

        /*
         * 朴素贝叶斯
         * 最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型（Naive Bayesian Model，NBM）。
         * 和决策树模型相比，朴素贝叶斯分类器(Naive Bayes Classifier 或 NBC)发源于古典数学理论，有着坚实的数学基础，以及稳定的分类效率。
         * 同时，NBC模型所需估计的参数很少，对缺失数据不太敏感，算法也比较简单。
         * 理论上，NBC模型与其他分类方法相比具有最小的误差率。
         * 但是实际上并非总是如此，这是因为NBC模型假设属性之间相互独立，这个假设在实际应用中往往是不成立的，这给NBC模型的正确分类带来了一定影响。
         * */
        $classifier = new NaiveBayes();
        $classifier->train($samples, $labels);
        echo $classifier->predict([158, 45], [170, 30]); //输出-1，女性
    }

    // apriori关联性规则学习
    public function apriori()
    {
        /*
        一个电商网站 统计6位用户购买习惯
        A用户喜欢购买   衣服，鞋子, 辣条
        B用户喜欢购买   辣条, 面条, 席子
        C用户喜欢购买   衣服,席子, 面条
        D用户喜欢购买   衣服,面条,鞋子
        E用户喜欢购买   衣服, 面条, 辣条
        F用户喜欢购买   衣服, 鞋子, 辣条
        */
        /*将上面的数据放入$samples数组里
        */
        $samples = [['衣服', '鞋子', '辣条'], ['辣条', '面条', '席子'], ['衣服', '席子', '面条'], ['衣服', '面条', '鞋子'], ['衣服', '面条', '辣条'], ['衣服', '鞋子', '辣条']];
        $labels = [];
        /*
        参数
        support 支持度
        confidence 自信度
        */
        $associator = new Apriori($support = 0.5, $confidence = 0.5);
        /* 对其进行训练   */
        $associator->train($samples, $labels);
        /*
        假设又有一位G用户，他购买了衣服，
        电商网站想要通过他购买的衣服给她推荐别的产品
        以便他购买更多的商品
        系统会根据以往用户的训练数据推断出G用户可能需要的商品
        */
        print_r($associator->predict(['衣服']));
        //return  Array ( [0] => Array ( [0] => 鞋子 ) [1] => Array ( [0] => 辣条 ) [2] => Array ( [0] => 面条 ) )
        /*
        总结：这种算法根据一些行为来推断下一个行为
        */
    }

    // 回归预测
    public function predict()
    {
        /*
        我们现在对一支股票进行预测
        张氏股从2010年开始
        2010年单股价123.5$
        2011年单股价124.5$
        2012年单股价134.5$
        2013年单股价144$
        2014年单股价144.7$
        2015年单股价154.5$
        2016年单股价184.5$
        我们根据每年的股价涨势计算出
        2010年 涨1.1%
        2011年 涨1.2%
        2012年 涨2.1%
        2013年 涨3.1%
        2014年 涨3.3%
        2015年 涨4.1%
        2016年 涨5.1%
        */
        /*将上面的数据放入$samples数组里
        */
        $samples = [[2010], [2011], [2012], [2013], [2014], [2015], [2016]];
        /*
        在labels中存入每年的股价涨势
        */
        $labels = [1.1, 1.2, 2.1, 3.1, 3.3, 4.1, 5.1];
        /*
        下面我们采用最小二乘法逼近线性模型进行预测
        */
        $regression = new LeastSquares();

        /*
        下面我们采用libsvm的向量回归进行预测
        */
        $regression = new SVR(Kernel::LINEAR);

        /* 对其进行训练   */
        $regression->train($samples, $labels);
        /*
        如果我们想知道2017年张氏股的涨势是什么样的，我们用最小二乘法逼近线性模型来进行预测
        */
        print_r($regression->predict([2017]));
        // return 5.53667

        /*
        我们预测的结果是涨势5.53%
        该实例采用回归的最小二乘法算法和向量回归来进行预测的
        */
    }
    /*********************************************************php-ml业务智能测试*******************************************************/


    /*********************************************************php-ml人工智能测试*******************************************************/
    // 多元线性回归
    public function testAi()
    {
        $samples = [[73676, 1996], [77006, 1998], [10565, 2000], [146088, 1995], [15000, 2001], [65940, 2000], [9300, 2000], [93739, 1996], [153260, 1994], [17764, 2002], [57000, 1998], [15000, 2000]];//【里程 年份】
        $targets = [2000, 2750, 15500, 960, 4400, 8800, 7100, 2550, 1025, 5900, 4600, 4400]; // 价格
        $regression = new LeastSquares();
        $regression->train($samples, $targets);
        $res = $regression->predict([60000, 1996]); //计算出 1996 年，60000里程的车，预测价格 是  4094.82
        print_r($res);
        //return 4094.82
    }

    // 皮尔逊相关
    public function relations()
    {
        $x = [43, 21, 25, 42, 57, 59];
        $y = [99, 65, 79, 75, 87, 82];
        $res = Correlation::pearson($x, $y);
        print_r($res);
        //return 0.549
    }

    // 计算标准差
    public function standardDiff()
    {
        $population = [5, 6, 8, 9];
        $res = StandardDeviation::population($population);
        print_r($res);
        //return 1.825
        $population = [7100, 15500, 4400, 4400, 5900, 4600, 8800, 2000, 2750, 2550, 960, 1025];
        $res = StandardDeviation::population($population);
        print_r($res);
        //return 4079
    }

    // 近邻算法
    public function nearestNeighbors()
    {
        $samples = [[1, 3], [1, 4], [2, 4], [3, 1], [4, 1], [4, 2]];
        $labels = ['a', 'a', 'a', 'b', 'b', 'b'];
        $classifier = new KNearestNeighbors();
        $classifier->train($samples, $labels);
        $res = $classifier->predict([[3, 2], [1, 3]]);
        print_r($res); // return b a
    }

    // 先验算法
    public function aprioriTest()
    {
        // 根据数据列出样本，和提供的一个样本，算出含有提供的样本的所有数据（以数组形式返回）
        $samples = [['alpha', 'beta', 'epsilon'], ['alpha', 'beta', 'theta'], ['alpha', 'beta', 'epsilon'], ['alpha', 'beta', 'theta']];
        $labels = [];
        $associator = new Apriori($support = 0.5, $confidence = 0.5);
        $associator->train($samples, $labels);
        $res = $associator->predict(['alpha', 'theta']);
        print_r($res);
        // return [['beta']]

        $res = $associator->predict([['alpha', 'epsilon'], ['beta', 'theta']]);
        //print_r($res);
        // return [[['beta']], [['alpha']]]

        //获取生成的关联规则只需使用rules方法。
        $res = $associator->getRules();
        //print_r($res);
        // return [['antecedent' => ['alpha', 'theta'], 'consequent' => ['beta'], 'support' => 1.0, 'confidence' => 1.0], ... ]

        //生成k长度的频繁项集只需使用apriori方法即可。
        $res = $associator->apriori();
        //print_r($res);
        // return [ 1 => [['alpha'], ['beta'], ['theta'], ['epsilon']], 2 => [...], ...]
    }

    /*********************************************************php-ml人工智能测试*******************************************************/

    public function index()
    {
        return "beiqiaosu ma";

        $demo = new EsTool();
        //$res = $demo->getSource();
        $scriptRes = $demo->getScript();
        //$scriptRes = $demo->getAggs();

        return $scriptRes;

// var_dump($demo->getSource());die;


        // $ref = new \ReflectionClass($demo);
        // $funcList = $ref->getMethods();
        //
        // foreach ($funcList as $item) {
        //     $func = $item->name;
        //     $res = $demo->{$item->getName()}();
        //     $data[$item->getName()] = array(
        //         "title" => $item->getDocComment(),
        //         "func" => $item->getName(),
        //         "res" => array_slice($res, 0, 5),
        //     );
        // }
        //
        // p($data);
    }

    public function getMsg()
    {
        // $str = "您的订单还未支付，{{var_15}}分钟后将被关闭，快抓紧支付哦！ 不要错过你千挑万选的好宝贝";
        // $holder = "{{var}}";
        //
        // return preg_match("/var_[0-9]/", $str);
        //
        // //return "hello fff3598300fff";

        return Message::get(1, [5]);
    }

    public function callCommand()
    {

        // 调用命令行的指令
        $output = Console::call('sync:products', ['--num', '10', "25"]);

        // 获取输出信息
        return $output->fetch();
    }


    public function esSimpilar()
    {
        return app('es')->queryData('products', '12', 1);
    }

    // es请求参数构造器
    public function esBuilder()
    {
        $obj = new \app\common\helper\ProductSearchBuilder();
        return $obj->getParams();
    }


}
